Uber API Design Decisions
Understand the workflow and design considerations for the Uber API.
The API design for the Uber system is tricky because it has multiple services interacting under the hood to perform the desired functionalities. It involves a significant level of communication between the different types of users and the back-end services. Moreover, we also request data from third-party services like Google Maps. Therefore, we‘ll observe substantial technical considerations such as choosing an architectural style, data formats, and the protocol to communicate between the clients and services. Let's start the discussion with the design overview and then move on to the workflow and technical design considerations.
Design overview#
The high-level design of Uber consists of mainly three types of services defined below:
Back-end services: These services perform the core operations of handling requests from clients (riders and drivers), such as requesting a ride, maintaining the trip, tracking the locations of the driver and the rider, and so on.
Supporting services: The Google Maps service has a key role in providing an effective Uber service. It is responsible for the provision of the rider and driver's location. Other than that, the payment gateway service reliably transfers charges from the rider to the driver's account. The chat service allows the rider to chat with the driver until the driver arrives at the rider's pickup location.
Persistence layer: This layer stores various types of data for a variety of purposes. Other than storing user data, it maintains a history of different rides and completed trips to provide accurate and low-latency service by learning over time through technologies like machine learning (ML).
Some of the essential components and services that are involved in the design of the Uber API are given in the table below:
Components and Services Details
Component or Service | Details |
Rides service |
|
Rider service |
|
Driver service |
|
Trip service |
|
Pub-sub service |
|
API gateway |
|
Workflow of Uber API#
In this section, we'll discuss the complete workflow of different services to achieve the functional requirements.
Booking a ride: The rider sets the source and destination locations for the ride and requests an estimate of the charges from the ride service. The ride services provide the estimated cost for different vehicle types. Next, the rider can choose to book a ride by selecting the desired vehicle type. This request is again forwarded to the ride request, which collaborates with the driver service to acquire a list of potential drivers. As soon as the nominated drivers receive a notification from the ride service via pub-sub, one of the drivers accepts the request on a first-come-first-serve basis.
Trip flow: Once the trip starts, the trip services take charge of updating the driver and the rider on the state of the trip. It’s possible that the rider modifies the ride by adding stops to the trip via the trip service. In that case, the driver will get a notification, and the updated cost and ride status will be shared with both users. The driver can finally end the trip via the trip service.
Payment transfer: Upon successful completion of a trip, the driver service transfers the cut amount to the Uber account and sends the remaining amount to the driver account. It’s possible for the driver's service to transfer the payment to an account through a Stripe-like payment gateway.
The complete trip workflow is complex, including multiple service interactions such as request, trip, driver, Google Maps, payment, chat, and pub-sub services. The trip flow is depicted in the following illustration:
1 of 13
2 of 13
3 of 13
4 of 13
5 of 13
6 of 13
7 of 13
8 of 13
9 of 13
10 of 13
11 of 13
12 of 13
13 of 13
Note: After the payment process, the driver and rider can provide feedback about each other, which gets stored in the persistence layer through the driver and user services.
Points to Ponder
Question 5
How do riders and drivers communicate with each other?
The riders’ and drivers’ profile information can be obtained through the /riders and /drivers endpoints. This information is visible to the users once the driver accepts a rider’s request. Also, the riders and drivers can communicate with each other using a chat service.
5 of 5
Design considerations#
In this section, we’ll focus on the architectural style and protocols that require the clients to communicate with the back-end services. We’ll also discuss the data formats to be adopted in the design of our API.
Let's begin by deciding which architectural design will satisfy our needs for the Uber API.
Architectural styles#
Let's discuss the architecture style used between client and service by dividing it into the following two layers:
Client-to-API gateway: The Uber API mainly performs CRUD operations over resources, such as user, trip, and ride data. Generally, we retrieve available vehicles, obtain trip estimated cost and time, post user feedback, update profile information, and so on. Since all of these operations are best suited for a REST-type API, we opt for the REST API architecture style between the client and API gateway.
API gateway-to-back-end services: While there are multiple services to request for various reasons, the communication is not action-oriented, so gRPC is not the best choice. While REST is easily scalable, we can ensure scalability and asynchronous communication with the help of pub-sub. One main reason for selecting REST is that the APIs of our supporting services (Maps, etc.) are also RESTful, and our backend will need to call these APIs as per the REST architecture. Moreover, the API gateway is not fetching the data from multiple resources simultaneously, and there’s limited internal communication between services, which REST can conveniently handle.
Server-sent updates: The Uber services involve a bunch of live updates. Therefore, the role of pub-sub is not only attending to matters of scalability and asynchronous communication but also updating users (riders, drivers). Riders are updated on the completion of a trip, while drivers get notifications about the availability of a ride. We can’t use the request-response paradigms here because these updates are pushed from the server side to the client. Therefore, we use event-driven architecture to send the updates to the client.
Point to Ponder
Question
Can REST be a suitable option to use between back-end and supporting services?
Yes, REST is a suitable option here because Uber follows the request-response pattern to communicate with the supporting services. This communication happens for a short period. Moroever, we’re using third-party services like Google Maps, which provides its public-facing APIs in RESTful architecture. While it may seem like we require an event-driven architecture for a service like Google Maps, the Uber service requires obtaining directions only at the start of the trip. In case any update is needed during the trip (for instance, the user adds a new stop), a new request can be sent to the Google Maps service. Since such cases are not frequent, there’s no need to have a duplex or persistent event-driven connection between Uber and the supporting services.
Protocols#
We'll use the same communication protocol between the client to the API gateway and the API gateway to the back-end services. Therefore, we have divided this section into client-to-back-end services and server-sent updates, as given below:
Client-to-backend services: We use HTTP/1.1 for the communication between the client and server since the communication follows the request-response pattern. Moreover, the driver service gets the location of the driver after every few seconds. This is why we need a persistent connection between the driver and driver service. We use HTTP/1.1 with a
keep-aliveheader to achieve our requirements. Our service can’t benefit from the advantages that HTTP/2.0 has to offer. For example, riders and drivers send sequential requests, in which case multiplexing may not give us any significant performance gain. Therefore, there’s no need to add to the overall complexity.Server-sent updates: The pub-sub service uses the WebSub protocol to send updates from the server to the riders and drivers.
Data formats#
Let's understand the choice of data format for the Uber API:
Client-to-API gateway: The communication between the client and API gateway follows the REST architectural style, and it’s recommended that we should use JSON with the REST. Moreover, JSON is human-readable and provides ease to the developer during debugging.
Server-sent updates: The data formats between the server and the client also use JSON data format because it’s easily understandable by the developers and helps them interpret the response.
Summary#
In this lesson, we discussed the complete workflow of the Uber service and made different design decisions that are required to design efficient Uber APIs. The following table summarizes the design decisions that have been made in this lesson:
Design Considerations | Client-to-API Gateway | API Gateway-to-Backend Services | Server-Sent Updates |
Architecture style | REST | REST | Pub-sub |
Data format | JSON | JSON | JSON |
Communication protocol | HTTP/1.0 | HTTP/1.0 | WebSub |
Requirements of the Uber API
API Model for Uber Service